#pragma once

#include "ptr_traits.h"
#include "interlocks.h"

namespace marus
{
   using namespace ::std;
   using namespace ::std::tr1;
class  refcounted_base
{
protected:
    static const long FROZEN_COUNT = -1;

    mutable volatile long   _refs;

    refcounted_base()
        : _refs(0)
    {
        // must be aligned on a 32-bit boundary
        _ASSERT(PROPERLY_ALIGNED(_refs));

        if (__is_on_stack(this))
            interlocked32::set(_refs, FROZEN_COUNT);
    }

    refcounted_base(long refs_)
        : _refs(refs_)
    {
        // must be aligned on a 32-bit boundary
        _ASSERT(PROPERLY_ALIGNED(_refs));


        if (__is_on_stack(this))
        {
            if (!refs_)
                interlocked32::set(_refs, FROZEN_COUNT);
            _ASSERT(!refs_ && "reference counted object allocated on stack");
        }

    }

    ~refcounted_base()
    {
        _ASSERT(!_frozen() || !_in_use());
    }


    INLINE long FASTCALL _num_refs() const
    {
        return interlocked32::get(_refs);
    }

    FORCEINLINE bool FASTCALL _in_use() const
    {
        return 0 ==_num_refs();
    }

    INLINE bool FASTCALL _frozen() const
    {
        return FROZEN_COUNT == interlocked32::get(_refs);
    }

    INLINE long FASTCALL increment()
    {
        return interlocked32::increment(_refs);
    }

    INLINE long FASTCALL decrement()
    {
        return interlocked32::decrement(_refs);
    }

    INLINE bool FASTCALL safe_increment_refs()
    {
        return interlocked32::increment_ne<FROZEN_COUNT>(_refs);
    }

    INLINE bool FASTCALL safe_decrement_refs()
    {
        return interlocked32::decrement_ne<FROZEN_COUNT>(_refs);
    }

public:
};

template<typename TClass>
class   refcounted : public refcounted_base
{
public:
    typedef typename TClass _Derived_t;
protected:

    refcounted(long initialref_)
        : refcount_base(initialref_)
    {}
public:

    refcounted()
        : refcounted_base()
    {
    }

    ~refcounted()
    {
    }

    INLINE
    operator TClass* () 
    {
        return static_cast<TClass*>(this);
    }

    INLINE
    operator const TClass* () const 
    {
        return static_cast<TClass*>(this);
    }

    INLINE
    operator TClass& () 
    {
        _ASSERT(this != NULL);
        //ENSURE(this != NULL);
        return *static_cast<TClass*>(this);
    }

    INLINE
    operator const TClass& () const 
    {
        _ASSERT(this != NULL);
        //ENSURE(this != NULL);
        return *static_cast<TClass*>(this);
    }

    ULONG AddRef()
    {
        safe_increment_refs();
        __if_exists(TClass::OnAddRef){
        TClass* pThis = (TClass*)this;
        pThis->OnAddRef();
        }
        return _num_refs();
    }

    ULONG Release()
    {
        if (safe_decrement_refs())
        {
            _ASSERT(_num_refs() >= 0);
            if (!_num_refs())
            {
                TClass* pThis = (TClass*)this;
                __if_exists(TClass::FinalRelease){  
                pThis->FinalRelease(); }
                delete pThis;
                return 0;
            }
        }
        __if_exists(TClass::OnRelease){
            TClass* pThis = (TClass*)this;
            pThis->OnRelease();
        }
        return _num_refs();
    }
};


template <typename T, class policy = default_policy<T> >
class   _ptr
{
public:
    typedef _ptr<T, policy>  _Myt;
    typedef policy                  _Traits;
    typedef typename _Traits::_Type     _Type;
    typedef typename _Traits::pointer    pointer;
    typedef typename _Traits::const_pointer    const_pointer;
    typedef typename _Traits::reference    reference;
    typedef typename _Traits::const_reference    const_reference;

    friend  class _ptr;

protected:
    mutable pointer _p;
    reference _Ref() const
    {
        return _p;
    }

public:


    _Myt()
        : _p(0)
    {}


    _Myt(pointer p_)
        : _p(_Traits::acquire(p_))
    {}

    _Myt(const_pointer p_)
        : _p(_Traits::acquire(p_))
    {}

    //_Myt(const T& ref_)
    //    : _p(_Traits::acquire(&ref_))
    //{}

    _Myt(const _Myt& ref_)
        : _p(NULL)
    {
        _Traits::copy(_p, ref_._Ref());
    }

    template <typename _OtherT>
    _Myt(const _OtherT* p_)
        : _p(_Traits::acquire(p_)) // NULL
    {
    }

    template <typename _OtherT, typename _OtherTraits >
    _Myt(const _ptr<_OtherT, _OtherTraits>& ref_)
        : _p(NULL)
    {
        _Traits::copy(_p, ref_._Ref());
    }

    ~_ptr()
    {
        _Traits::release(_p);
    }

    pointer _pointer() const
    {
        return _p;
    }

    const_pointer _const_pointer() const
    {
        return _p;
    }

    template <typename _Other>
    operator _STD auto_ptr_ref<_Other>()
    {
		_Other* ret = 0;
        _Traits::copy(ret, _p);
        return _STD auto_ptr_ref<_Other>(ret);
    }

    template <typename _Other>
    void    attach(const _Other* p_, bool accept_ = false)
    {
        pointer tmp = _Traits::cast(p_);
        if (tmp != _p)
        {
            if (accept_)
                _Traits::acquire(tmp);
            _Traits::release(_p) = tmp;
        }
    }

    pointer detach() const
    {
        return _Traits::detach(_p);
    }

    inline
    typename _Traits::_RefType operator*() // reference 
    {
        return *_p;
    }

    inline
    pointer* operator&()  // address of
    {
        _Traits::release(_p); 
        return &_p;
    }

    inline
    pointer operator->() 
    {
        return _p;
    }

    const_pointer operator->() const 
    {
        return _p;
    }

    operator pointer () const
    {
        return _p;
    }

    operator const_pointer () const
    {
        return _p;
    }

    operator bool() const
    {
        return _p != NULL;
    }

    bool    operator!() const
    {
        return _p == NULL;
    }

    bool    operator==(int null_) const
    {
        _ASSERT(null_ == 0);
        return _p == NULL;
    }

    bool    operator!=(int null_) const
    {
        return !(operator==(null_));
    }

    bool    operator==(const_pointer p_) const
    {
        return _p == p_;
    }

    bool    operator!=(const_pointer p_) const
    {
        return !(operator==(p_));
    }

    _Myt&   operator=(const_pointer right_)
    {
        _Traits::copy(_p, right_);
        return *this;
    }

    template <typename _OtherT, typename _OtherTraits>  
    bool operator==(const _ptr<_OtherT, _OtherTraits>& ref_)
    {
        return _p == _Traits::cast(ref_._const_pointer());
    }

    template <typename _OtherT, typename _OtherTraits>  
    bool operator!=(const _ptr<_OtherT, _OtherTraits>& ref_)
    {
        return !(operator == (ref_));
    }

    template <typename _OtherT>  
    _Myt& operator=(const _OtherT* p_)
    {
        _Traits::copy(_p, p_);
        return *this;
    }

    template <typename _OtherT, typename _OtherTraits>  
    _Myt& operator=(const _ptr<_OtherT, _OtherTraits>& ref_)
    {
        _Traits::copy(_p, ref_._Ref());
        return *this;
    }

    _Myt&   operator=(const _Myt& ref_)
    {
        _Traits::copy(_p, ref_._Ref());
        return *this;
    }

	_Myt& operator=(_STD auto_ptr_ref<_Type> ref_)
	{
        _Traits::copy(_p, ref_._Ref);
		return (*this);
	}
};

template <typename _Ty> 
class SmartPtr : public _ptr<_Ty, refcounted_policy<_Ty> >
{
public:
    typedef _ptr<_Ty, refcounted_policy<_Ty> > _Parent_t;
    typedef typename _Parent_t::_Type  _Type;

    typedef SmartPtr<_Ty> _Myt;
    SmartPtr()
        : _ptr()
    {
    }

    SmartPtr (_Type* p_)
        : _ptr(p_)
    {
    }

    SmartPtr (_Type& ref_)
        : _ptr(&ref_)
    {
    }

    SmartPtr(const _Myt& ref_)
        : _ptr(ref_)
    {
    }

    template <typename _OtherT>
    SmartPtr(const _OtherT* p_)
        : _ptr(p_)
    {
    }

    template <typename _OtherT>
    SmartPtr(const SmartPtr<_OtherT>& ref_)
        : _ptr(ref_)
    {
    }

    ~SmartPtr()
    {
    }

    //INLINE operator _STD _Bool_type() const
    //{	// test if object owns no resource
    //    return (_p != 0 ? _CONVERTIBLE_TO_TRUE : 0);
    //}


    _Myt&  operator=(_Type* p_)
    {
        return (_Myt&)_Parent_t::operator=(p_);
    }

    _Myt& operator=(const _Myt& ref_)
    {
        return (_Myt&)_Parent_t::operator=(ref_);
    }

    template <typename _OtherT>  
    _Myt& operator=(_OtherT* p_)
    {
        return (_Myt&)_Parent_t::operator=(p_);
    }

    template <typename _OtherT>  
    _Myt& operator=(const SmartPtr<_OtherT>& ref_)
    {
        return (_Myt&)_Parent_t::operator=(ref_);
    }
};

template<typename _Ty>
	class WeakRef;
template<typename _Ty>
	class Reference;
template<typename _Ty>
	class joint;
template<typename _Ty>
	class shareable;

template <const bool is_shareable = false>
class share_enabler {
public:
   static inline void Do(const volatile void*, const volatile void*)
   {
      // not derived from shareable<>; do nothing
   }
};

template <>
class share_enabler<true>{
public:
   template<typename _Ty>
   static inline void Do(_Ty* _Ptr, joint<_Ty>* _share)
   {
      // reset internal weak pointer
      if (_Ptr)
      {
         ((shareable<_Ty>*)_Ptr)->_Do_enable(_share);
      }
   }
};
//
//class _Init {
//public:
//   template<typename _Ty>
//   static inline void _shared(_Ty *_Ptr)
//   {
//      share_enabler<__is_base_of( shareable<_Ty>, _Ty) >::Do(_Ptr);
//   }
//};

//#define _Init_shared(p) _Init::_shared(p)

template<typename _Ty>
class joint
{
private:
    joint();
protected:
    template <typename _Ty0>
    friend class share_holder;
    typedef _ptr<_Ty, typename policies<_Ty>::life_span >  _Pointer_t;
    typedef typename policies<_Ty>::caster  _Caster_t;

    _Pointer_t          _pointer;
    volatile    long    _weak_count;
    volatile    long    _strong_count;

    joint(_Ty* p_)
        : _pointer(p_)
        , _weak_count(1)
        , _strong_count(0)
    {
    }

    // increment use count if not zero, return true if successful
    INLINE bool _Incref_nz()
    {	
        return interlocked32::increment_nz(_strong_count);
    }

    // increment use count
    INLINE void _Incref() 
    {	
        interlocked32::increment(_strong_count);
    }

    // increment weak reference count
    INLINE void _Incwref()
    {
        interlocked32::increment(_weak_count);
    }

    // decrement strong reference count
    void FASTCALL _Decref()
    {	
        if (interlocked32::decrement(_strong_count) == 0)
        {	// destroy managed resource, decrement weak reference count
            _pointer = NULL;
            _Decwref();
        }
    }

    // decrement weak reference count
    INLINE  void _Decwref()
    {	
        if (interlocked32::decrement(_weak_count) == 0)
            delete this;
    }

    // return use count
    INLINE long _Use_count() const
    {	
        return interlocked32::get((volatile long&)_strong_count);
    }

    // return true if _strong_count == 0
    INLINE  bool _Expired() const
    {   
        return (_Use_count() == 0);
    }

    INLINE const volatile _Ty *_Getptr() const
    {	// return stored pointer
        return (_pointer._const_pointer());
    }
};

template<typename _Ty>
class   share_holder
{
protected:
    typedef typename _Ty    _Elem;
    typedef _Elem element_type;
    template <typename _Ty0>
    friend class share_holder;

    typedef class joint<_Elem>    _Share_t;
    typedef typename _Share_t::_Pointer_t    _Pointer_t;
    typedef typename _Share_t::_Caster_t    _Caster_t;

    _Share_t*      _share;
    typedef share_holder<_Ty> _Myt;
    template <typename _Ty2>
    friend class shareable;

    share_holder()
        : _share(0)
    {	
    }

    INLINE  _Ty *_Get() const
    {	// return pointer to resource
        return (_share ? const_cast<_Ty*> (_share->_Getptr()) : 0);
    }

    INLINE bool _Expired() const
    {
        return (!_share || _share->_Expired());
    }

    // decrement strong reference count
    INLINE  void _Decref()
    {
        if (_share != 0)
            _share->_Decref();
    }

    // decrement weak reference count
    INLINE  void _Decwref()
    {
        if (_share != 0)
            _share->_Decwref();
    }


    // release resource
    INLINE  void _Reset()
    {	
        _Decref();
        _share = NULL;
    }

    INLINE void set_share(_Share_t*   _Other) 
    {
       _share = _Other;
       share_enabler<__is_base_of( shareable<_Ty>, _Ty) >::Do(_Get(), _share);
    }

    // release resource and take ownership of _Other._share
    template<class _Ty2>
    INLINE  void _Reset(const share_holder<_Ty2>& _Other)
    {	
        _Resetp0(_Other._share); //, _TR1 _Dynamic_tag());
    }

    // release resource and take ownership from WeakRef _Other._share
    template<class _Ty2>
    INLINE  void _Reset(const share_holder<_Ty2>& _Other, bool _Throw)
    {	
        _Reset((_Share_t*)_Other._share, _Throw);
    }

    template<class _Ty2>
    void _Reset(const share_holder<_Ty2>& _Other, const //_TR1 
       _Static_tag&)
    {	// release resource and take ownership of _Other._share
        _Reset((_Share_t*)(_Other._share));
    }

    template<class _Ty2>
    void _Reset(const share_holder<_Ty2>& _Other, const //_TR1 
       _Const_tag&)
    {	// release resource and take ownership of _Other._share
        _Reset((_Share_t*)(_Other._share));
    }
    template<class _Ty2>
    void _Reset(const share_holder<_Ty2>& _Other, const //_TR1 
       _Dynamic_tag& tag_)
    {	// release resource and take ownership of _Other._share
        _Ty2* other = _Other._Get();
        typename _Caster_t::_Type my = _Caster_t::cast(other); //, tag_);
        if (my)
        {
            if ((const void*)my == (const void*)other)
                _Reset((_Share_t*)_Other._share);
            else
                _Resetp(my);
        }
        else
            _Reset();
    }

    template<class _Ty2>
    INLINE  void _Reset(_STD auto_ptr<_Ty2>& _Other)
    {	// release resource and take _Other.get()
        _Ty2 *_Px = _Other.get();
        _Reset(new _Share_t(_Px));
        _Other.release();
    }

    void FASTCALL _Reset(_Share_t*   _Other)
    {	// release resource and take _Other
        if (_Other)
            _Other->_Incref();
        _Decref();
        set_share(_Other);
    }

    void FASTCALL _Reset(_Share_t* _Other, bool _Throw)
    {	// take _Other from WeakRef if not expired
        // otherwise, leave in default state if !_Throw,
        // otherwise throw exception
        if (_Other && _Other->_Incref_nz())
        {   // take pointers
            _Decref();
            set_share(_Other);
        }
        else if (_Throw)
            _THROW_NCEE(_TR1 bad_weak_ptr, 0); // _TR1 _Xweak();
    }

    INLINE  void _Resetw()
    {	// release weak reference to resource
        _Resetw((_Share_t*)0);
    }

    // release weak reference to resource and take _Other._share
    template<class _Ty2>
    INLINE  void _Resetw(const share_holder<_Ty2>& _Other)
    {	
        _Resetw(_Other._share);
    }

    template<class _Ty2>
    INLINE  void _Resetw(const joint<_Ty2> *_Other)
    {	// point to _Other
        _Resetw(const_cast< joint<_Ty2>* >(_Other));
    }

    template<class _Ty2>
    void FASTCALL _Resetw(joint<_Ty2>* _Other)
    {	// point to _Other
        if (_share != _Other) 
        {
           if (_Other)
               _Other->_Incwref();
           _Decwref();
           _share = (_Share_t*)_Other;
        }
    }

    template<class _Ux>
    void FASTCALL _Resetp(_Ux *_Px)
    {	// release, take ownership of _Px
        _Resetp( best_cast<_Elem>(_Px));
    }

    void FASTCALL _Resetp(_Elem *_Px)
    {	// release, take ownership of _Px
        if (_Px == _Get())
            return;
        _TRY_BEGIN	// allocate control block and reset
            _Reset(new _Share_t(_Px));
        _CATCH_ALL	// allocation failed, delete resource
            delete _Px;
        _RERAISE;
        _CATCH_END
    }

    template<class _Ux>
    INLINE void _Resetp0(joint<_Ux> *_Rx)
    {	// release resource and take ownership of _Px
        _Ux* other = (_Rx)?const_cast<_Ux*>(_Rx->_Getptr()) : NULL ;
        if (other)
        {
            typename cast_result<_Elem>::_Type my(best_cast<_Elem>(other));
            if ((const void*)my == (const void*)other)
                _Reset((_Share_t*)_Rx);
            else
                _Resetp(my);
        }
        else
            _Reset();
    }

    INLINE void _Resetp0(_Share_t* _Rx)
    {	// release resource and take ownership of _Px
        _Reset(_Rx);
    }

public:

    INLINE long use_count() const
    {	// return use count
        return (_share ? _share->_Use_count() : 0);
    }

    INLINE void _Swap(share_holder& _Other)
    {	// swap pointers
        _STD swap(_share, _Other._share);
    }

    template<class _Ty2>
    INLINE  bool _Cmp(const share_holder<_Ty2>& _Right) const
    {	// compare addresses of manager objects
        return (_share < _Right._share);
    }

    INLINE bool unique() const
    {	// return true if no other Reference object owns this resource
        return (use_count() == 1);
    }

    IMPLEMENT_SAFE_BOOL_OPERATOR(_Get() != 0)
    ////INLINE operator _STD _Bool_type() const
    ////{	// test if Reference object owns no resource
    ////    return (_Get() != 0 ? _CONVERTIBLE_TO_TRUE : 0);
    ////}
    //_TYPEDEF_BOOL_TYPE;
    //INLINE _OPERATOR_BOOL //operator _STD _Bool_type
    //   () const 
    //   throw()
    //{	// test if object owns no resource
    //    return (_Get() != 0 ? _CONVERTIBLE_TO_TRUE : 0);
    //}

};

template<class _Ty>
void swap(share_holder<_Ty>& _1, share_holder<_Ty>& _2)
{	// swap contents of _1 and _2
    _1._Swap(_2);
}

template<
    class _Ty1, 
    class _Ty2
>
bool operator<(const share_holder<_Ty1>& _1,  const share_holder<_Ty2>& _2)
{	// return true if _1 precedes _2 (order defined by control block)
    return (_1._Cmp(_2));
}


template<typename _Ty>
class   Reference : public share_holder<_Ty>
{
public:

    Reference()
    {	// construct empty Reference object
        _Reset();
    }

    template<typename _Ux>
    explicit Reference(_Ux *_Px)
    {	// construct Reference object that owns *_Px
        _Resetp(_Px);
    }

    Reference(const Reference& _Other)
    {	// construct Reference object that owns same resource as _Other
        _Reset(_Other);
    }

    template<class _Ty2>
    Reference(const Reference<_Ty2>& _Other)
    {	// construct Reference object that owns same resource as _Other
        _Reset(_Other);
    }

    template<class _Ty2>
    explicit Reference(const WeakRef<_Ty2>& _Other,
        bool _Throw = false)
    {	// construct Reference object that owns resource *_Other
        _Reset(_Other, _Throw);
    }

    template<class _Ty2>
    explicit Reference(_STD auto_ptr<_Ty2>& _Other)
    {	// construct Reference object that owns *_Other.get()
        _Reset(_Other);
    }

    template<class _Ty2>
    Reference(const Reference<_Ty2>& _Other, const //_TR1 
       _Static_tag& _Tag)
    {	// construct Reference object for static_pointer_cast
        _Reset(_Other, _Tag);
    }

    template<class _Ty2>
    Reference(const Reference<_Ty2>& _Other, const //_TR1 
       _Const_tag& _Tag)
    {	// construct Reference object for const_pointer_cast
        _Reset(_Other, _Tag);
    }

    template<class _Ty2>
    Reference(const Reference<_Ty2>& _Other, const //_TR1 
       _Dynamic_tag& _Tag)
    {	// construct Reference object for dynamic_pointer_cast
        _Reset(_Other, _Tag);
    }

    ~Reference()
    {	// release resource
        _Decref();
    }

    INLINE Reference& operator=(const Reference& _Right)
    {	// assign shared ownership of resource owned by _Right
        _Reset(_Right);
        return (*this);
    }

    template<class _Ty2>
    INLINE Reference& operator=(const Reference<_Ty2>& _Right)
    {	// assign shared ownership of resource owned by _Right
        _Reset(_Right);
        return (*this);
    }

    template<class _Ty2>
    INLINE Reference& operator=(_STD auto_ptr<_Ty2>& _Right)
    {	// assign ownership of resource pointed to by _Right
        _Reset(_Right);
        return (*this);
    }

    INLINE void reset()
    {	// release resource and convert to empty Reference object
        _Reset();
    }

    template<class _Ux>
    INLINE void reset(_Ux *_Px)
    {	// release, take ownership of _Px
        _Resetp(_Px);
        //_Init_shared(_Px);
    }

    INLINE void swap(Reference& _Other)
    {	// swap pointers
        _Swap(_Other);
    }

    INLINE _Ty *get() const
    {	// return pointer to resource
        return (_Get());
    }

    INLINE typename _TR1 add_reference<_Ty>::type operator*() const
    {	// return reference to resource
        return (*_Get());
    }

    INLINE _Ty *operator->() const
    {	// return pointer to resource
        return (_Get());
    }

};

template<typename _Ty>
class   WeakRef : public share_holder<_Ty>
{
public:
    WeakRef()
    {	// construct empty WeakRef object
        _Resetw();
    }

    template<class _Ty2>
    WeakRef(const Reference<_Ty2>& _Other)
    {	// construct WeakRef object for resource owned by _Other
        _Resetw(_Other);
    }

    WeakRef(const WeakRef& _Other)
    {	// construct WeakRef object for resource pointed to by _Other
        _Resetw(_Other);
    }

    template<class _Ty2>
    WeakRef(const WeakRef<_Ty2>& _Other)
    {	// construct WeakRef object for resource pointed to by _Other
        _Resetw(_Other);
    }

    ~WeakRef()
    {	// release resource
        _Decwref();
    }

    INLINE WeakRef& operator=(const WeakRef& _Right)
    {	// assign from _Right
        _Resetw(_Right);
        return (*this);
    }

    template<class _Ty2>
    INLINE WeakRef& operator=(const WeakRef<_Ty2>& _Right)
    {	// assign from _Right
        _Resetw(_Right);
        return (*this);
    }

    template<class _Ty2>
    INLINE WeakRef& operator=(Reference<_Ty2>& _Right)
    {	// assign from _Right
        _Resetw(_Right);
        return (*this);
    }

    INLINE void reset()
    {	// release resource, convert to null WeakRef object
        _Resetw();
    }

    INLINE void swap(WeakRef& _Other)
    {	// swap pointers
        _Swap(_Other);
    }

    INLINE bool expired() const
    {	// return true if resource no longer exists
        return (_Expired());
    }

    INLINE Reference<_Ty> lock() const
    {	// convert to Reference
        return (Reference<_Elem>(*this, false));
    }
};

template<typename _Ty>
class shareable { // provide member functions that create Reference to shareable type
public:
   
   typedef typename _Ty _shareable_type;

   Reference<_Ty> SharedRef()
   {	// return shared_ptr
      return (Reference<_Ty>(_Wptr));
   }

   Reference<const _Ty> SharedRef() const
   {	// return shared_ptr
      return (Reference<const _Ty>(_Wptr));
   }

protected:
   shareable() _NOEXCEPT
   {	// construct (do nothing)
   }

   shareable(const shareable&) _NOEXCEPT
   {	// construct (do nothing)
   }

   shareable&
      operator=(const shareable&) _NOEXCEPT
   {	// assign (do nothing)
      return (*this);
   }

   ~shareable() _NOEXCEPT
   {	// destroy (do nothing)
   }

private:
   friend class share_enabler<true>;
   template<class _Ty2>
   inline void _Do_enable(joint<_Ty2>* _share) 
   {
         _Wptr._Resetw(_share);
   }

   mutable WeakRef<_Ty> _Wptr;
};

template<
    class _Ty1,
    class _Ty2
>
bool operator==(const Reference<_Ty1>& _S1, const Reference<_Ty2>& _S2)
{	// test if Reference objects hold pointers that compare equal
    return (_S1.get() == _S2.get());
}

template<
    class _Ty1,
    class _Ty2
>
bool operator!=(const Reference<_Ty1>& _S1, const Reference<_Ty2>& _S2)
{	// test if Reference objects hold pointers that compare unequal
    return (!(_S1 == _S2));
}

template<
    class _Elem,
    class _Traits,
    class _Ty
>
_STD basic_ostream<_Elem, _Traits>&  operator<<(_STD basic_ostream<_Elem, _Traits>& _Out, const Reference<_Ty>& _Px)
{	// write contained pointer to stream
    return (_Out << _Px.get());
}


#if 1
template<
    class _Ty1,
    class _Ty2
>
Reference<_Ty1> static_pointer_cast(const Reference<_Ty2>& _Other)
{	// return Reference object holding static_cast<_Ty1 *)(_Other.get())
    return (Reference<_Ty1>(_Other, _TR1 _Static_tag()));
}

template<
    class _Ty1,
    class _Ty2
>
Reference<_Ty1> const_pointer_cast(const Reference<_Ty2>& _Other)
{	// return Reference object holding const_cast<_Ty1 *)(_Other.get())
    return (Reference<_Ty1>(_Other, _TR1 _Const_tag()));
}

template<
    class _Ty1,
    class _Ty2
>
Reference<_Ty1> dynamic_pointer_cast(const Reference<_Ty2>& _Other)
{	// return Reference object holding dynamic_cast<_Ty1*)(_Other.get())
    return (Reference<_Ty1>(_Other, //_TR1 
       _Dynamic_tag()));
}


#endif
} // namespace marus

template<typename T>
struct  marus_sharing
{
    typedef marus::Reference<T>   strong;
    typedef marus::WeakRef<T>     weak;
};

template<typename T>
struct  std_sharing
{
    typedef _TR1 shared_ptr<T>  strong;
    typedef _TR1 weak_ptr<T>  weak;
};

template<typename _Ty>
struct  sharing
{
    typedef typename
        _STD _If <
        (marus::_is_refcounted<_Ty>::value 
        || marus::_is_atlcom_type<_Ty>::value
        || marus::_is_com_type<_Ty>::value )
        , marus_sharing<_Ty>
        , std_sharing<_Ty>
        >::type _Type;

    typedef typename _Type::strong  strong;
    typedef typename _Type::weak    weak;
};

#define IS_REFCOUNTED  1
#define IS_COMTYPE     2
#define IS_ATLCOMOBJECT 4

#define FORCE_CLASS_POLICY(_Class, flags)\
class _Class;\
template<> struct marus::_is_refcounted<_Class> { enum { value = (flags)& IS_REFCOUNTED}; };\
template<> struct marus::_is_com_type<_Class> { enum { value = (flags)& IS_COMTYPE}; };\
template<> struct marus::_is_atlcom_type<_Class> {enum {value = (flags)& IS_ATLCOMOBJECT}; };\

